package com.adminx.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.adminx.util.PageResults;

/**
 * DAO基类，其它DAO可以直接继承这个DAO，不但可以复用共用的方法，还可以获得泛型的好处�?
 */
public class BaseDao<T, ID extends Serializable> {
	
	@Autowired
	private SessionFactory sessionFactory;
	
	protected Class<T> entityClass;

	public BaseDao() {

	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected Class getEntityClass(){
		if (entityClass == null){
			entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return entityClass;
	}
 
	/**
	 * <保存实体>
	 * <完整保存实体>
	 * @param t 实体参数
	 */
	public void save(T t) {
		this.getSession().save(t);
	}

	/**
	 * <保存或�?更新实体>
	 * @param t 实体
	 */
	public void saveOrUpdate(T t) {
	    this.getSession().saveOrUpdate(t);
	}
	 
	/**
	 * <load>
	 * <加载实体的load方法>
	 * @param id 实体的id
	 * @return 查询出来的实�?
	 */
	@SuppressWarnings("unchecked")
	public T load(ID id) {
	    T load = (T) this.getSession().load(getEntityClass(), id);
	    return load;
	}
	 
	/**
	 * <get>
	 * <查找的get方法>
	 * @param id 实体的id
	 * @return 查询出来的实�?
	 */
	@SuppressWarnings("unchecked")
	public T get(ID id) {
	    T load = (T) this.getSession().get(getEntityClass(), id);
	    return load;
	}
	 
	/**
	 * <contains>
	 * @param t 实体
	 * @return 是否包含
	 */
	public boolean contains(T t) {
		return this.getSession().contains(t);
	}
	
	/**
	 * <delete>
	 * <删除表中的t数据>
	 * @param t 实体
	 */
	public void delete(T t) {
		this.getSession().delete(t);
	}
	 
	/**
	 * <根据ID删除数据>
	 * @param Id 实体id
	 * @return 是否删除成功
	 */
	public boolean deleteById(ID Id) {
		T t = get(Id);
		if(t == null){
			return false;
		}
		delete(t);
		return true;
	}

	/**
	 * <删除�?��>
	 * @param entities 实体的Collection集合
	 */
	public void deleteAll(Collection<T> entities) {
		for(Object entity : entities) {
			this.getSession().delete(entity);
		}
	}
 
	/**
	 * <执行Hql语句>
	 * @param hqlString hql
	 * @param values 不定参数数组
	 */
	public void queryHql(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		query.executeUpdate();
	}
 
	/**
	 * <执行Sql语句>
	 * @param sqlString sql
	 * @param values 不定参数数组
	 */
	public void querySql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		query.executeUpdate();
	}
	
	
	/**
	 * <执行Sql语句获取总条�?
	 * @param sqlString sql
	 * @param values 不定参数数组
	 */
	public BigInteger countSql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		return (BigInteger)query.list().get(0);
	}
	
	/**
	 * <根据HQL语句查找唯一实体>
	 * @param hqlString HQL语句
	 * @param values 不定参数的Object数组
	 * @return 查询实体
	 */
	@SuppressWarnings("unchecked")
	public T getByHQL(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		return (T) query.uniqueResult();
	}

	/**
	 * <根据SQL语句查找唯一实体>
	 * @param sqlString SQL语句
	 * @param values 不定参数的Object数组
	 * @return 查询实体
	 */
	@SuppressWarnings("unchecked")
		public T getBySQL(String sqlString, Object... values) {
			Query query = this.getSession().createSQLQuery(sqlString);
			if (values != null){
				for (int i = 0; i < values.length; i++){
					query.setParameter(i, values[i]);
				}
			}
			return (T) query.uniqueResult();
		}

	/**
	 * <根据HQL语句，得到对应的list>
	 * @param hqlString HQL语句
	 * @param values 不定参数的Object数组
	 * @return 查询多个实体的List集合
	 */
	@SuppressWarnings("unchecked")
	public List<T> getListByHQL(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	/**
	 * <根据SQL语句，得到对应的list>
	 * @param sqlString HQL语句
	 * @param values 不定参数的Object数组
	 * @return 查询多个实体的List集合
	 */
	@SuppressWarnings("unchecked")
	public List<T> getListBySQL(String sqlString, Object... values ) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	@SuppressWarnings("unchecked")
	public List<Object> getListBySQL2(String sqlString, Object... values ){
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	/**
	 * <refresh>
	 * @param t 实体
	 */
	public void refresh(T t) {
		this.getSession().refresh(t);
	}

	/**
	 * <update>
	 * @param t 实体
	*/
	public void update(T t) {
		this.getSession().update(t);
	}

	/**
	 * <根据HQL得到记录�?
	 * @param hql HQL语句
	 * @param values 不定参数的Object数组
	 * @return 记录总数
	 */
	public Long countByHql(String hql, Object... values) {
		Query query = this.getSession().createQuery(hql);
		if(values != null){
			for(int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return (Long) query.uniqueResult();
	}

	/**
	 * <HQL分页查询>
	 * @param hql HQL语句
	 * @param countHql 查询记录条数的HQL语句
	 * @param pageIndex 当前页码
	 * @param pageSize 每页条数
	 * @param values 不定Object数组参数
	 * @return PageResults的封装类，里面包含了页码的信息以及查询的数据List集合
	 */
	@SuppressWarnings("unchecked")
	public PageResults<T> findPageByFetchedHql(String hql, String countHql,
			int pageIndex, int pageSize, Object... values) {
		PageResults<T> retValue = new PageResults<T>();
		Query query = this.getSession().createQuery(hql);
		if(values != null){
			for(int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		int currentPage = pageIndex > 1 ? pageIndex : 1;
		retValue.setPageIndex(currentPage);
		retValue.setPageSize(pageSize);
		
		if (countHql == null){
			ScrollableResults results = query.scroll();
			results.last();
			retValue.setTotal(results.getRowNumber() + 1);// 设置总记录数
		}
		else{
			int count = countByHql(countHql, values).intValue();
			
			if(count%pageSize==0&&count/pageSize>0){
				retValue.setPageCount(count/pageSize);
			}else{
				retValue.setPageCount(count/pageSize+1);
			}
			retValue.setTotal(count);
		}
		
		List<T> itemList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).list();
		if (itemList.size() == 0){
			itemList = new ArrayList<T>();
			retValue.setPageCount(1);
		}
		retValue.setResults(itemList);
		
		return retValue;
	}
	
	
	/**
	 * <SQL分页查询> (重载)
	 * @param cls pojo类
	 * @param sql 查询语句
	 * @param countSql 查询记录条数的SQL语句
	 * @param pageIndex 当前页
	 * @param pageSize 一页总条数
	 * @param values 不定Object数组参数
	 * @return PageResults
	 */
	@SuppressWarnings("unchecked")
	public <E> PageResults<E> findPageByFetchedSql(Class<E> cls, String sql, String countSql, int pageIndex, int pageSize, Object... values){
	
		//pageResult分页数据
		PageResults<E> pageResults = new PageResults<E>();
		
		StringBuffer sb = new StringBuffer(sql);
		//给sql追加查询位置条件
		//sb.append(" LIMIT " + ((pageIndex - 1) * pageSize) + "," + pageSize);
		//创建查询
		Query query = this.getSession().createSQLQuery(sb.toString());
		//设置参数
		if (values != null){
			for (int i = 0; i < values.length; i++){
				query.setParameter(i, values[i]);
			}
		}
		//查出数据
		//List<E> clsList = query.setResultTransformer(Transformers.aliasToBean(cls)).list();
		int currentPage = pageIndex > 1 ? pageIndex : 1;
		List<E> clsList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).setResultTransformer(Transformers.aliasToBean(cls)).list();
		//封装当前页数据
		pageResults.setResults(clsList);
		//进行数据库计数
		BigInteger count = this.countSql(countSql, values);
		//封装每页条数
		pageResults.setPageSize(pageSize);
		//封装信息总条数
		pageResults.setTotal(count.intValue());
		//封装当前页页数
		pageResults.setPageIndex(pageIndex);
		//页数统计
		Integer pageCount;
		//如果总数刚好够分整数页 : 页数 = 条数 / 每页大小
		if (count.intValue() % pageSize == 0 && count.intValue() / pageSize > 0) {
			pageCount = count.intValue() / pageSize;
		}
		//如果总数有零散数 : 页数 = 条数 / 每页大小 + 1
		else {
			pageCount = count.intValue() / pageSize + 1;
		}
		//封装页数
		pageResults.setPageCount(pageCount);
		return pageResults;
	}
	
	/**
	 * 根据Criterion条件创建Criteria.
	 * 与find()函数可进行更加灵活的操作.
	 * 
	 * @param criterions 数量可变的Criterion.
	 */
	public Criteria createCriteria(final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(entityClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}

	/**
	 * 按Criteria查询对象列表.
	 * 
	 * @param criterions 数量可变的Criterion.
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(final Criterion... criterions) {
		return createCriteria(criterions).list();
	}

	/**
	 * 按属性查找对象列�? 匹配方式为相�?
	 */
	public List<T> findBy(final String propertyName, final Object value) {
		Assert.hasText(propertyName, "propertyName不能为空");
		Criterion criterion = Restrictions.eq(propertyName, value);
		return find(criterion);
	}
	
	/**
	 * 判断对象的属性�?在数据库内是否唯�?
	 * 
	 * 在修改对象的情景�?如果属�?新修改的�?value)等于属�?原来的�?(orgValue)则不作比�?
	 */
	public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue) {
		if (newValue == null || newValue.equals(oldValue)) {
			return true;
		}
		Object object = findUniqueBy(propertyName, newValue);
		return (object == null);
	}
	
	/**
	 * 按属性查找唯�?���? 匹配方式为相�?
	 */
	@SuppressWarnings("unchecked")
	public T findUniqueBy(final String propertyName, final Object value) {
		Assert.hasText(propertyName, "propertyName不能为空");
		Criterion criterion = Restrictions.eq(propertyName, value);
		return (T) createCriteria(criterion).uniqueResult();
	}
	
	/**
	 *	获取全部对象, 支持按属性行�?
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll(String orderByProperty, boolean isAsc) {
		Criteria c = createCriteria();
		if (isAsc){
			c.addOrder(Order.asc(orderByProperty));
		}else {
			c.addOrder(Order.desc(orderByProperty));
		}
		return c.list();
	}
 
	/**
	 * @return the sessionFactory
	 */
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * @param sessionFactory the sessionFactory to set
	 */
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * 
	 * @return session
	 */
	public Session getSession() {
		//�?���?��事物，才能得到CurrentSession
		return sessionFactory.getCurrentSession();
	}
}